package org.admin.controller;

import core.Data;
import core.data.DataHandle;
import core.data.DataResult;
import org.admin.entity.domain.Entry;
import org.admin.entity.domain.User;
import org.admin.entity.dto.EntryDto;
import org.admin.entity.vo.EntryCaptchaVo;
import org.admin.entity.vo.EntryRefreshVo;
import org.admin.service.RedisService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.admin.service.EntryService;

import java.util.*;
@RestController
@RequestMapping("/admin/entry")
public class EntryController {
    @Autowired
    private EntryService service;
    @Autowired
    private RedisService redisService;
    // 刷新 Token, 包含创建、更新以及检查合法性。
    @PostMapping("/refresh")
    public DataResult refresh(@RequestBody Map<String, Object> post){
        return Data.create(post)
                .<EntryDto>addHandle("params", data -> {
                        // 校验 token 令牌
                        new EntryDto().validate(new String[] { "token" }).check(data, new EntryDto());
                    }).<EntryRefreshVo>addHandle("refresh", data -> {
                    // 刷新 Token
                    service.refresh(data);
                }).start().getResult();
    }

    @GetMapping ("/captcha")
    public DataResult captcha(@RequestParam Map<String, Object> get){
        return Data.create(get)
                .<EntryDto>addHandle("params", data -> {
                    // 校验 token 令牌
                    new EntryDto().validate(new String[] { "*token" })
                            .check(data);
                }).<EntryCaptchaVo>addHandle("captcha", data -> {
                    // 生成验证码
                    service.captcha(data);
                }).start().getResult();
    }

    @PostMapping ("/login")
    public DataResult login(@RequestBody Map<String, Object> post) {
        return Data.create(post)
                .<EntryDto>addHandle("token", data -> {
                    new EntryDto().validate(new String[] {"*token"}).check(data);
                }).addHandle("entry", service::query)
                .onSuccess(DataHandle::publish)
                .<EntryDto>addHandle("params", data -> {
                    List<String> rules = new ArrayList<>();
                    rules.add("*username");
                    rules.add("*password");
                    rules.add("*always");
                    Entry entry = data.getParams();
                    // 判断是否使用Captcha?
                    DataHandle<Map<String, Object>, EntryDto> checkHandle = data.setHandle(post, "check");
                    if(entry.getStateWith() == Entry.STATE.FAILURE
                        || entry.getFailureCount() >= Entry.FAILURE_COUNT
                        && entry.getFailureAt().getTime() + Entry.FAILURE_TIME >= System.currentTimeMillis()){
                        rules.add("*captcha");
                        new EntryDto(redisService).validate(rules.toArray(new String[0]))
                                .check(checkHandle);
                    }else {
                        new EntryDto().validate(rules.toArray(new String[0]))
                                .check(checkHandle);
                    }
                    data.setData(checkHandle.getData());
                    data.start();
                }).<User>addHandle("login", service::login)
                .onSuccess(data -> {
                    //登录成功
                    Entry entry = data.getGlobal("entry");
                    boolean always = data.getParams().getAlways();
                    Date expiredAt = null;
                    if(always){
                        expiredAt = new Date(System.currentTimeMillis() + Entry.ALWAYS_TIME_OUT);
                    }else{
                        expiredAt = new Date(System.currentTimeMillis() + Entry.TIME_OUT);
                    }
                    entry.setExpiredAt(expiredAt);
                    entry.setUserId(data.getData().getId());
                    service.pullSuccess(entry);
                    // 清除数据
                    data.data.clear();
                }).onFailure(data -> {
                    Entry entry = data.getGlobal("entry");
                    if(entry != null) {
                        service.pullFailure(entry);
                    }
                }).start().getResult();
    }

    @PostMapping ("/logout")
    public DataResult logout(@RequestBody Map<String, Object> post){
        return Data.create(post)
                .<EntryDto>addHandle("params", data -> {
                    new EntryDto().validate(new String[] {"*token"}).check(data);
                }).addHandle("logout", service::logout)
                .start().getResult();
    }

}
